package com.easylinkin.linkappapi.quality.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.common.utils.excel.ExcelConstant;
import com.easylinkin.linkappapi.common.utils.excel.ExcelTools;
import com.easylinkin.linkappapi.common.utils.io.OutputStreamUtil;
import com.easylinkin.linkappapi.quality.dto.ActualMeasureDetailsDTO;
import com.easylinkin.linkappapi.quality.dto.ActualMeasureInfoDTO;
import com.easylinkin.linkappapi.quality.dto.ActualMeasureTopDTO;
import com.easylinkin.linkappapi.quality.dto.ActualMeasureValueDTO;
import com.easylinkin.linkappapi.quality.entity.ActualMeasureDetails;
import com.easylinkin.linkappapi.quality.entity.ActualMeasureInfo;
import com.easylinkin.linkappapi.quality.entity.ActualMeasureValue;
import com.easylinkin.linkappapi.quality.entity.vo.ActualMeasureDetailsVo;
import com.easylinkin.linkappapi.quality.entity.vo.ActualMeasureInfoVo;
import com.easylinkin.linkappapi.quality.mapper.ActualMeasureDetailsMapper;
import com.easylinkin.linkappapi.quality.mapper.ActualMeasureInfoMapper;
import com.easylinkin.linkappapi.quality.mapper.ActualMeasureValueMapper;
import com.easylinkin.linkappapi.quality.service.ActualMeasureInfoService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import site.morn.rest.RestBuilders;
import site.morn.rest.RestMessage;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * ActualMeasureInfo表服务实现类
 *
 * @author zhengwen
 * @date 2022/09/01
 */
@Slf4j
@Service("actualMeasureInfoService")
public class ActualMeasureInfoServiceImpl extends ServiceImpl
        <ActualMeasureInfoMapper, ActualMeasureInfo> implements ActualMeasureInfoService {
    @Resource
    private CommonService commonService;
    @Resource
    private LinkappUserContextProducer linkappUserContextProducer;

    @Resource
    private ActualMeasureDetailsMapper actualMeasureDetailsMapper;

    @Resource
    private ActualMeasureValueMapper actualMeasureValueMapper;

    @Override
    public boolean saveOne(ActualMeasureInfo appQualityActualMeasureInfo) {
        commonService.setCreateAndModifyInfo(appQualityActualMeasureInfo);
        // appQualityActualMeasureInfo.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        validParamRequired(appQualityActualMeasureInfo);
        validRepeat(appQualityActualMeasureInfo);
        validParamFormat(appQualityActualMeasureInfo);
        return save(appQualityActualMeasureInfo);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOne(ActualMeasureInfo appQualityActualMeasureInfo) {
        Assert.notNull(appQualityActualMeasureInfo.getId(), "id不能为空");
        commonService.setModifyInfo(appQualityActualMeasureInfo);
        //appQualityActualMeasureInfo.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        validRepeat(appQualityActualMeasureInfo);
        validParamFormat(appQualityActualMeasureInfo);
        return updateById(appQualityActualMeasureInfo);
    }

    @Override
    public IPage<ActualMeasureInfo> selectPage(Page page, ActualMeasureInfo appQualityActualMeasureInfo) {
        //appQualityActualMeasureInfo.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        return baseMapper.selectPage(page, appQualityActualMeasureInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteByIds(List<Long> idList) {
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        //级联删除测试点信息
        if(CollectionUtil.isNotEmpty(idList)){
            Date now = DateUtil.date();
            idList.stream().forEach(infoId ->{
                //删除详情
                UpdateWrapper<ActualMeasureDetails> detailsUw = new UpdateWrapper<>();
                detailsUw.eq("info_id",infoId);
                detailsUw.set("delete_state",0);
                detailsUw.set("modify_time",now);
                detailsUw.set("modifier",linkappUser.getId().toString());
                actualMeasureDetailsMapper.update(null,detailsUw);
                //删除测试点
                UpdateWrapper<ActualMeasureValue> valueUw = new UpdateWrapper<>();
                valueUw.eq("info_id",infoId);
                valueUw.set("delete_state",0);
                valueUw.set("modify_time",now);
                valueUw.set("modifier",linkappUser.getId().toString());
                actualMeasureValueMapper.update(null,valueUw);
            });
        }
        return removeByIds(idList);
    }

    @Override
    public void export(ActualMeasureInfo appQualityActualMeasureInfo, HttpServletRequest request, HttpServletResponse
            response) {

        IPage<ActualMeasureInfo> page = selectPage(new Page(0, -1), appQualityActualMeasureInfo);
        List<ActualMeasureInfo> records = page.getRecords();
        List
                <ActualMeasureInfoVo> appQualityActualMeasureInfoVos = new ArrayList<>();
        for (ActualMeasureInfo expert : records) {
            appQualityActualMeasureInfoVos.add(new ActualMeasureInfoVo(expert));
        }

        String keyValue = "名称:name,租户id:tenantId";
        String title = "ActualMeasureInfo导出数据";
        String fileName = title + ".xls";
        try {
            OutputStream outputStream = OutputStreamUtil
                    .getOutputStream(request, response, fileName);
            ExcelTools.exportExcel(outputStream, keyValue, appQualityActualMeasureInfoVos, ExcelConstant.XLS, title);
            response.flushBuffer();
            outputStream.close();
        } catch (IOException e) {
            log.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！IOException异常" + e.getMessage());
        } catch (Exception e) {
            log.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！" + e.getMessage());
        }
    }

    @Override
    public RestMessage saveMeasureInfoData(ActualMeasureInfoVo actualMeasureInfoVo) {
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        //参数校验
        cn.hutool.core.lang.Assert.notNull(actualMeasureInfoVo.getPositionId(), "测量部位不能为空");

        List<ActualMeasureDetailsVo> detailsVoList = actualMeasureInfoVo.getDetailsList();
        Assert.isTrue(CollectionUtil.isNotEmpty(detailsVoList), "测量项目不能为空");
        cn.hutool.core.lang.Assert.notNull(actualMeasureInfoVo.getStorageType(), "保存方式不能为空");
        cn.hutool.core.lang.Assert.notNull(actualMeasureInfoVo.getActualOrgType(), "实测单位不能为空");
        cn.hutool.core.lang.Assert.notNull(actualMeasureInfoVo.getSubOrgId(), "分包单位不能为空");

        ActualMeasureInfo actualMeasureInfo = saveOrUpdateMeasureInfo(actualMeasureInfoVo, linkappUser);

        return RestBuilders.successBuilder().build();
    }

    @Override
    public IPage<ActualMeasureInfoDTO> selectDtoPage(Page page, ActualMeasureInfoVo actualMeasureInfoVo) {
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        Boolean onlySelf = actualMeasureInfoVo.getOnlySelf();
        if (onlySelf != null && onlySelf) {
            actualMeasureInfoVo.setCreator(linkappUser.getId().toString());
        }
        actualMeasureInfoVo.setTenantId(linkappUser.getTenantId());
        IPage<ActualMeasureInfoDTO> list = baseMapper.selectDtoPage(page, actualMeasureInfoVo);
        List<ActualMeasureInfoDTO> recordLs = list.getRecords();
        //计算总合格率
        if (CollectionUtil.isNotEmpty(recordLs)) {
            recordLs.stream().forEach(r -> {
                AtomicInteger okNum = new AtomicInteger();
                AtomicInteger inNum = new AtomicInteger();
                r.setTotalPassRate(0d);
                List<ActualMeasureDetailsDTO> detailsList = r.getDetailsList();
                if (CollectionUtil.isNotEmpty(detailsList)) {
                    detailsList.stream().forEach(d -> {
                        List<ActualMeasureValueDTO> valueLs = d.getActualMeasureValueList();
                        if (CollectionUtil.isNotEmpty(valueLs)) {
                            valueLs.stream().forEach(v -> {
                                Integer actualState = v.getActualState();
                                if (actualState != null) {
                                    if (actualState.intValue() == 1) {
                                        okNum.getAndIncrement();
                                    }
                                    inNum.getAndIncrement();
                                }
                            });
                        }
                    });
                }
                if (okNum.get() != 0 && inNum.get() != 0) {
                    double totalRate = NumberUtil.div(okNum.get(), inNum.get(), 4);
                    r.setTotalPassRate(totalRate);
                }
            });
        }
        return list;
    }

    @Override
    public RestMessage getOneDto(Long id) {
        cn.hutool.core.lang.Assert.notNull(id, "id不能为空");
        ActualMeasureInfoDTO dto = baseMapper.selectOneDto(id);
        return RestBuilders.successBuilder().data(dto).build();
    }

    @Override
    public RestMessage selectTabNum(ActualMeasureInfoVo actualMeasureInfoVo) {
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        actualMeasureInfoVo.setTenantId(linkappUser.getTenantId());
        Map<String, Integer> mp = new HashMap<>();
        int totalNum = baseMapper.selectDtoPageCount(actualMeasureInfoVo);
        actualMeasureInfoVo.setCreator(linkappUser.getId().toString());
        int myNum = baseMapper.selectDtoPageCount(actualMeasureInfoVo);

/*
        QueryWrapper<ActualMeasureInfo> qw = new QueryWrapper<>();
        qw.eq("tenant_id",linkappUser.getTenantId());
        qw.eq("delete_state",1);
        int totalNum = baseMapper.selectCount(qw);
        qw.eq("creator",linkappUser.getId().toString());
        int myNum = baseMapper.selectCount(qw);
       */
        mp.put("totalNum", totalNum);
        mp.put("myNum", myNum);
        return RestBuilders.successBuilder().data(mp).build();
    }

    private ActualMeasureInfo saveOrUpdateMeasureInfo(ActualMeasureInfoVo actualMeasureInfoVo, LinkappUser linkappUser) {
        Date now = DateUtil.date();
        Integer storageType = actualMeasureInfoVo.getStorageType();
        if (storageType.intValue() == 2) {
            actualMeasureInfoVo.setMeasureTime(now);
        }

        ActualMeasureInfo actualMeasureInfo = new ActualMeasureInfo();
        Long id = actualMeasureInfoVo.getId();
        if (id == null) {
            BeanUtil.copyProperties(actualMeasureInfoVo, actualMeasureInfo, CopyOptions.create().setIgnoreNullValue(true));
            actualMeasureInfo.setMeasureTime(now);
            actualMeasureInfo.setTenantId(linkappUser.getTenantId());
            actualMeasureInfo.setCreator(linkappUser.getId().toString());
            actualMeasureInfo.setCreateTime(now);
            actualMeasureInfo.setModifyTime(now);
            actualMeasureInfo.setModifier(actualMeasureInfo.getCreator());
            actualMeasureInfo.setDeleteState(1);
            this.baseMapper.insert(actualMeasureInfo);
        } else {
            BeanUtil.copyProperties(actualMeasureInfoVo, actualMeasureInfo, CopyOptions.create().setIgnoreNullValue(false));
            actualMeasureInfo.setModifyTime(now);
            actualMeasureInfo.setModifier(linkappUser.getId().toString());
            this.baseMapper.updateById(actualMeasureInfo);
        }

        //详情和测试值
        List<ActualMeasureDetailsVo> detailsVoList = actualMeasureInfoVo.getDetailsList();
        //先删除原先的详情、测试值
        QueryWrapper qw = new QueryWrapper<>();
        qw.eq("info_id", id);
        actualMeasureDetailsMapper.delete(qw);
        actualMeasureValueMapper.delete(qw);

        //重新保存
        if (CollectionUtil.isNotEmpty(detailsVoList)) {
            detailsVoList.stream().forEach(d -> {
                ActualMeasureDetails details = new ActualMeasureDetails();
                BeanUtil.copyProperties(d, details, CopyOptions.create().setIgnoreProperties("id", "infoId"));
                details.setInfoId(actualMeasureInfo.getId());
                details.setCreator(linkappUser.getId().toString());
                details.setDeleteState(1);
                details.setCreateTime(now);
                details.setModifyTime(now);
                details.setModifier(linkappUser.getId().toString());
                actualMeasureDetailsMapper.insert(details);

                List<ActualMeasureValue> valueLs = d.getActualMeasureValueList();
                if (CollectionUtil.isNotEmpty(valueLs)) {
                    valueLs.stream().forEach(v -> {
                        ActualMeasureValue value = new ActualMeasureValue();
                        BeanUtil.copyProperties(v, value, CopyOptions.create().setIgnoreProperties("infoId", "detailsId"));
                        value.setInfoId(details.getInfoId());
                        value.setDetailsId(details.getId());
                        value.setDeleteState(1);
                        value.setCreateTime(now);
                        value.setModifyTime(now);
                        value.setCreator(linkappUser.getId().toString());
                        value.setModifier(linkappUser.getId().toString());
                        actualMeasureValueMapper.insert(value);
                    });
                }
            });
        }

        return actualMeasureInfo;
    }

    @Override
    public ActualMeasureInfo getOneById(Serializable id) {
        return baseMapper.getOneById(id);
    }

    /**
     * 校验重复
     */
    private void validRepeat(ActualMeasureInfo appQualityActualMeasureInfo) {
        /* QueryWrapper<ActualMeasureInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", appQualityActualMeasureInfo.getName());
        queryWrapper.eq("tenant_id", linkappUserContextProducer.getNotNullCurrent().getTenantId());
        List<ActualMeasureInfo> list = baseMapper.selectList(queryWrapper);
        if (list.size() == 0) {
            return;
        }
        if (list.size() > 1) {
            throw new BusinessException("名称有重复");
        }
        if (ObjectUtils.isEmpty(appQualityActualMeasureInfo.getId())) {
            throw new BusinessException("名称已存在");
        }
        if (!appQualityActualMeasureInfo.getId().equals(list.get(0).getId())) {
            throw new BusinessException("名称已存在");
        }
                    */

    }


    /**
     * 校验参数必填
     */
    private void validParamRequired(ActualMeasureInfo appQualityActualMeasureInfo) {
        //Assert.notNull(appQualityActualMeasureInfo, "参数为空");
        //Assert.isTrue(StringUtils.isNotBlank(appQualityActualMeasureInfo.getName()), "名称为空");
    }

    /**
     * 校验参数格式
     */
    private void validParamFormat(ActualMeasureInfo appQualityActualMeasureInfo) {
        //Assert.isTrue(appQualityActualMeasureInfo.getName() == null || appQualityActualMeasureInfo.getName().length() <= 50,
        //        "名称超长");
    }

    @Override
    public List<ActualMeasureTopDTO> selectTopByOrg() {
        ActualMeasureInfo actualMeasureInfo = new ActualMeasureInfo();
        actualMeasureInfo.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        return baseMapper.selectTopByOrg(actualMeasureInfo);
    }

    @Override
    public List<ActualMeasureTopDTO> selectTopByType() {
        ActualMeasureInfo actualMeasureInfo = new ActualMeasureInfo();
        actualMeasureInfo.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        return baseMapper.selectTopByType(actualMeasureInfo);
    }

    @Override
    public ActualMeasureInfoDTO getOneDtoById(Long id) {
        ActualMeasureInfoDTO dto = baseMapper.selectOneDto(id);
        return dto;
    }
}

